import * as TWEEN from '@tweenjs/tween.js';
import * as D3 from 'd3-geo';
import { loadGeojson } from './request';

/**
 * 相机飞行动画函数
 * @param {Object} camera - 相机对象
 * @param {Object} target - 目标位置
 * @param {Object} controls - 控制器对象
 * @param {number} duration - 动画持续时间（毫秒）
 * @returns {Object} TWEEN动画实例
 */
export const flyTo = (camera, target, controls, duration = 1000) => {
  const startPosition = camera.value.position.clone();
  const startLookAt = controls.value.target.clone();
  const targetPosition = target.clone();
  const targetLookAt = target.clone();
  targetLookAt.y = 0;

  const tween = new TWEEN.Tween({
    x: startPosition.x,
    y: startPosition.y,
    z: startPosition.z,
    lookAtX: startLookAt.x,
    lookAtY: startLookAt.y,
    lookAtZ: startLookAt.z,
  })
    .to(
      {
        x: targetPosition.x,
        y: targetPosition.y,
        z: targetPosition.z,
        lookAtX: targetLookAt.x,
        lookAtY: targetLookAt.y,
        lookAtZ: targetLookAt.z,
      },
      duration
    )
    .easing(TWEEN.Easing.Quadratic.InOut)
    .onUpdate((e) => {
      camera.value.position.set(e.x, e.y, e.z);
      controls.value.target.set(e.lookAtX, e.lookAtY, e.lookAtZ);

      // 以下代码在特定情况下可能需要启用：
      // 1. 当controls的enableDamping为false时，需要手动更新相机
      // controls.value.position0.set(e.x, e.y, e.z)
      // camera.value.lookAt(e.x, e.y, e.z)
      // camera.value.updateProjectionMatrix()
      // controls.value.update()

      // 2. 如果相机移动后视角被重置，需要设置相机的up向量
      // <TresPerspectiveCamera :up="[0, 0, -1]" />
    })
    .start()
    .onComplete(() => {
      tween.stop();
    });

  return tween;
};

/**
 * 原生相机飞行动画函数（适用于非Vue组件）
 * @param {Object} camera - 相机对象
 * @param {Object} target - 目标位置
 * @param {Object} controls - 控制器对象
 * @param {Array} offsetZ - Z轴偏移量 [x偏移, z偏移]
 * @param {number} duration - 动画持续时间（毫秒）
 * @returns {Object} TWEEN动画实例
 */
export const flyToNative = (
  camera,
  target,
  controls,
  offsetZ = [-2000, -2000],
  duration = 1000
) => {
  const startPosition = camera.position.clone();
  const startLookAt = controls.target.clone();
  const targetPosition = target.clone();
  const targetLookAt = target.clone();
  targetLookAt.y = 0;
  targetLookAt.x = targetLookAt.x + offsetZ[0];
  targetLookAt.z = targetLookAt.z + offsetZ[1];

  const tween = new TWEEN.Tween({
    x: startPosition.x,
    y: startPosition.y,
    z: startPosition.z,
    lookAtX: startLookAt.x,
    lookAtY: startLookAt.y,
    lookAtZ: startLookAt.z,
  })
    .to(
      {
        x: targetPosition.x,
        y: targetPosition.y,
        z: targetPosition.z,
        lookAtX: targetLookAt.x,
        lookAtY: targetLookAt.y,
        lookAtZ: targetLookAt.z,
      },
      duration
    )
    .easing(TWEEN.Easing.Quadratic.InOut)
    .onUpdate((e) => {
      camera.position.set(e.x, e.y, e.z);
      controls.target.set(e.lookAtX, e.lookAtY, e.lookAtZ);
    })
    .start()
    .onComplete(() => {
      tween.stop();
    });

  return tween;
};

/**
 * 获取线条点数据函数
 * @param {string} geojson - GeoJSON文件路径
 * @returns {Promise<Array>} 处理后的点数据数组
 */
export const getlinePoints = async (geojson) => {
  const linePrimary = await loadGeojson(geojson);
  // 墨卡托投影转换
  const projection = D3.geoMercator()
    .center(linePrimary[0].properties.center)
    .translate([0, 0])
    .scale(1000);
  const points = [];
  linePrimary[0].geometry.coordinates[0].forEach((iOne) => {
    iOne.forEach((lineOne) => {
      const [x, y] = projection(lineOne);
      points.push([x, 0, y]);
    });
  });
  return points;
};
